
using System.Collections.Generic;
using UnityEngine;

namespace Ants.Utilities
{
    public class Geometry2D
    {
        public static TangentInfo2D GetTangentInfo(Vector2 projectorPos, Circle s, bool isClockWise = false)
        {
            float c = (s.center - projectorPos).magnitude, b = s.radius;
            float a = Mathf.Sqrt(c * c - b * b);
            Complex delta=new Complex(a,b);
            Complex pA=new Complex(s.center-projectorPos);
            Vector2 pC;
            if (!isClockWise)
            {
                pC= (pA * delta.normalized).toVec2;
            }
            else
            {
                pC= (pA / delta.normalized).toVec2;    
            }
            
            return  new TangentInfo2D(projectorPos+pC,pC.normalized);
        }
        
        public static void GetTangentInfoPair(Vector2 projectorPos, Circle s, out TangentInfo2D clockWise,out TangentInfo2D antiClockWise)
        {
            float c = (s.center - projectorPos).magnitude, b = s.radius;
            float a = Mathf.Sqrt(c * c - b * b);
            Complex delta=new Complex(a,b);
            Complex pA=new Complex(s.center-projectorPos);
            Vector2 pC;

                pC= (pA * delta.normalized).toVec2;
                antiClockWise.worldPos = projectorPos + pC;
                antiClockWise.dir = pC.normalized;
                pC= (pA / delta.normalized).toVec2;    
                clockWise.worldPos = projectorPos + pC;
                clockWise.dir = pC.normalized;
        }

        public static bool IsOnLeftSide(Vector2 a, Vector2 forward)
        {
            return forward.x * a.y - forward.y * a.x > 0;
        }
        
        
        
        //注意这里传入的几何体和投影点往往都是定义在世界空间下的
        public static void GetMinSector(Vector2 projectorPos, Polygon2D connectedSet, out TangentInfo2D lMost,out TangentInfo2D rMost)
        {
            lMost.dir = rMost.dir = lMost.worldPos = rMost.worldPos = Vector2.zero;
            Vector2 forward = connectedSet.GeomCenter - projectorPos;
            float lMostCos = 1f;
            float rMostCos = 1f;
            foreach (var wp in connectedSet.points)
            {
                Vector2 lp = wp - projectorPos;
                float sqrCos = Math.SqrCosineOf(lp, forward)*Mathf.Sign(Vector2.Dot(lp,forward));
                if (IsOnLeftSide(lp, forward))
                {
                    if (sqrCos< lMostCos)
                    {
                        lMostCos = sqrCos;
                        lMost.worldPos = wp;
                        lMost.dir = lp;
                    }
                }
                else
                {
                    if (sqrCos< rMostCos)
                    {
                        rMostCos = sqrCos;
                        rMost.worldPos = wp;
                        rMost.dir = lp;
                    }
                }

            }
            
        }
        public static Vector2 RotVec2(Vector2 v, float angle)
        {
            Complex c=new Complex(v);
            angle *= Const.DEGREE_TO_ARC;
            Complex delta=new Complex(Mathf.Cos(angle),Mathf.Sin(angle));
            return (c * delta).toVec2;
        }
        /*
         * 两向量方向基本一致(注意这包括两向量方向相反)
         */
        public static bool IsDirAligned(Vector2 a, Vector2 b)
        {
            return Math.EqualsZero(1-Math.SqrCosineOf(a,b));
        }

        /*
         * 以XY轴为平面
         */
        public static Vector2 ModelTransformXY2D(Transform t,Vector2 local)
        {
            local.Scale(t.transform.lossyScale);
            local = RotVec2(local, t.rotation.eulerAngles.z);
            local +=new Vector2(t.transform.position.x,t.transform.position.y);
            return local;
        }
        public static Vector2 InverseModelTransformXY2D(Transform t,Vector2 local)
        {
            local -=new Vector2(t.transform.position.x,t.transform.position.y);
            local = RotVec2(local, -t.rotation.eulerAngles.z);
            local.Scale(new Vector2(1/t.transform.lossyScale.x,1/t.transform.lossyScale.y));
            
            
            return local;
        }
    }

}

